In diesem Kapitel schauen wir uns den Representational State Transfer genauer an. Representational State Transfer (REST) bezeichnet vielmehr ein Programmierparadigma für verteilte Systeme, insbesondere für Webservices. Ein Webservice ermöglicht die Maschine-zu-Maschine-Kommunikation auf Basis von HTTP oder HTTPS über Rechnernetze. REST liegt also über HTTP. Dabei werden Daten ausgetauscht und auf entfernten Computern Funktionen aufgerufen. Jeder Webservice besitzt einen URI, über den er eindeutig identifizierbar ist, sowie eine Schnittstellenbeschreibung, die definiert, wie mit dem Webservice zu interagieren ist. Die Kommunikation erfolgt typischerweise über Protokolle aus dem Internetkontext wie XML oder JSON. REST hat das Ziel, einen Architekturstil zu schaffen, der die Anforderungen des modernen Web besser darstellt. Dabei unterscheidet sich REST vor allem in der Forderung nach einer einheitlichen Schnittstelle von anderen Architekturstilen. REST stellt eine einfache Alternative zu ähnlichen Verfahren wie SOAP und WSDL und dem verwandten Verfahren RPC dar. Anders als bei vielen verwandten Architekturen kodiert REST keine Methodeninformation in den URI, da der URI Ort und Namen der Ressource angibt, nicht aber die Funktionalität, die der Web-Dienst zu der Ressource anbietet. Der Vorteil von REST liegt darin, dass im WWW bereits ein Großteil der für REST nötigen Infrastruktur, wie Web- und Application-Server, HTTP-fähige Clients, HTML- und XML-Parser sowie Sicherheitsmechanismen vorhanden ist. Eine Ressource kann dabei über verschiedene Medientypen dargestellt werden, auch Repräsentation der Ressource genannt. Die Bezeichnung „Representational State Transfer“ soll den Übergang vom aktuellen Zustand zum nächsten Zustand einer Applikation verbildlichen. Dieser Zustandsübergang erfolgt durch den Transfer der Daten, die den nächsten Zustand repräsentieren. Jede REST-Nachricht enthält alle Informationen, die für den Server beziehungsweise Client notwendig sind, um die Nachricht zu verstehen. Weder der Server noch die Anwendung soll Zustandsinformationen zwischen zwei Nachrichten speichern. Man spricht daher von einem zustandslosen Protokoll. Jede Anfrage eines Clients an den Server ist insofern in sich geschlossen, als sie sämtliche Informationen über den Anwendungszustand beinhaltet, die vom Server für die Verarbeitung der Anfrage benötigt werden. Im Folgenden werde ich ein komplexeres REST-Beispiel vorstellen, nämlich das Tradingtool zum Abrufen von Börsendaten. Im Internet ist das testbar unter https frank dopatka de tradingtool. In dem Screenshot sehen Sie, wie über ein REST HTTP GET Kommando über einen Webbrowser die Kursdaten der Daimler-Aktie ab Januar zweitausendachtzehn abgerufen werden. Es sind Tageskurse mit Angaben zur Eröffnung (open), Schluss (close), Tageshoch (high) und Tagestief (low). Außerdem wird das Handelsvolumen angegeben. Schauen wir uns die Anfrage genauer an. Get-Kursreihe ist der Aufruf eines Dienstes, einer Funktion im Tradingtool. Diese Funktion hat zwei Eingabeparameter, die in der URL hintereinander geschrieben werden. Der erste Parameter ist die ISIN. Das ist eine ID, die die Daimler-Aktie eindeutig identifiziert. Der zweite Parameter ist ein Datum. Durch ein Reload der Seite wird ein Polling ausgelöst, indem man nochmal dieselbe Anfrage an den Server stellt. Schauen wir ins Backend, wie man solche Funktionen realisieren kann. Dies geschieht hier mit PHP. Damit das einfach funktioniert, muss man zunächst die h-t-access Datei im Tradingtool-Ordner schreiben und alle Anfragen an den Ordner auf die index php Datei umleiten. Ansonsten würde sowohl die aufgerufene Funktion, als auch deren Parameter jeweils als Unterordner zu Tradingtool angesehen werden, die natürlich nicht existieren. In der index-Datei wird dann die URI zerlegt, um bestimmte Teile davon für die weitere Verarbeitung zu extrahieren. Dabei wird zunächst die URI von der Server-Variable abgerufen, die beispielsweise die Adresse einer Webanwendung mit zusätzlichen Pfadinformationen enthält. Diese URI wird dann in ihre einzelnen Segmente zerlegt, indem die Schrägstriche als Trennzeichen verwendet werden. Jedes Segment wird dabei in einem Array gespeichert. Ein bestimmtes Segment, in diesem Fall das dritte Segment, wird als Dienst oder Aktion interpretiert, zum Beispiel getKursreihe. Die darauf folgenden Segmente der URI werden als Parameter betrachtet, wie etwa eine Identifikationsnummer und ein Datum. Schließlich wird die Anzahl der Parameter ermittelt, um festzustellen, wie viele zusätzliche Informationen in der URI enthalten sind. Nun wird der konkrete Dienst und die Anzahl der Parameter, die in der URI enthalten sind, weiterverarbeitet. Dazu wird eine switch-Struktur verwendet, um den Dienst zu identifizieren, der in der URI angegeben ist. Ein Beispiel dafür ist der Dienst getKursreihe. Abhängig von der Anzahl der Parameter, die zuvor aus der URI extrahiert wurden, wird die weitere Verarbeitung gesteuert. Wenn genau ein Parameter vorhanden ist, wird eine bestimmte Aktion ausgeführt, die hier jedoch nicht weiter spezifiziert wird. Falls zwei Parameter vorhanden sind, beispielsweise eine Wertpapierkennnummer und ein Datum, wird eine Verbindung zur MySQL-Datenbank hergestellt, um weitere Daten abzurufen. Die beiden Parameter werden dann in Variablen gespeichert. Anschließend wird der Inhaltstyp der Antwort auf json gesetzt, wodurch die Antwort im JSON-Format zurückgegeben wird. Schließlich wird eine Methode aufgerufen, die vermutlich die angeforderten Daten basierend auf den übergebenen Parametern zurückliefert. Die Kursreihe einer Aktie wird dann aus einer MySQL-Datenbank abgerufen und die entsprechenden Kursdaten werden verarbeitet. Die Methode, die dafür zuständig ist, erhält die Verbindungsinformationen zur Datenbank sowie bestimmte Parameter wie die ISIN und den Zeitraum, für den die Kurse benötigt werden. Zuerst wird ein SQL-Befehl vorbereitet, der die Kursdaten für die angegebene ISIN aus der Tabelle kursreihe der Datenbank abruft. Dazu wird ein sogenanntes Prepared Statement verwendet, um SQL-Injection-Angriffe zu verhindern und die Abfrage sicherer zu gestalten. Die ISIN wird dann als Parameter an das Prepared Statement gebunden, und die Abfrage wird ausgeführt. Die resultierenden Daten werden in einem assoziativen Array gespeichert. Anschließend wird ein neues Objekt der Klasse Kursreihe erstellt, das die Daten aufbereitet. Weitere Daten, wie der Zeitraum der Kurse, werden hinzugefügt, bevor das Objekt in eine JSON-Darstellung umgewandelt wird. Abschließend wird die Methode beschrieben, die das erstellte Kursreihe-Objekt in JSON konvertiert. Diese JSON-Daten werden dann zurückgegeben, wobei bestimmte Formatierungsoptionen angewendet werden, um das Ergebnis leserlicher und kompatibler zu gestalten, indem beispielsweise Schrägstriche nicht maskiert werden. Nun schauen wir uns ein alternatives Frontend an, diesmal in Javascript. Dabei wird zuerst ein HTML-Formular mit der ISIN und zwei Datumswerten aufgerufen. Dann wird (etwas unschön) die Javascript-Funktion hole Daten aufgerufen. Außerdem fällt ein noch leerer div-container auf. In diesem sollen die ausgelesenen Daten erscheinen. Nun werden die Werte aus den Eingabefeldern der Webseite für die ISIN und den Zeitraum von und bis abgefragt und in Variablen gespeichert. Ein neues XML-Http-Request-Objekt wird erstellt, um eine HTTP-Anfrage an den Server zu senden. In der onreadystatechange-Funktion wird überprüft, ob die Anfrage erfolgreich war und ob die Antwort vom Server vollständig vorliegt. Wenn dies der Fall ist, wird die Antwort, die im JSON-Format vorliegt, geparst und in ein JavaScript-Objekt umgewandelt. Anschließend wird der Inhalt der JSON-Daten in HTML-Elemente umgewandelt, um sie auf der Webseite anzuzeigen. Die ISIN, der Name der Aktie und die Anzahl der Kurse werden dabei in Textform dargestellt. Danach werden die einzelnen Kurse in einer Schleife durchlaufen und das jeweilige Datum sowie der Schlusskurs angezeigt. Diese Informationen werden dann in einem speziellen Container-Element auf der Webseite eingefügt. Zum Schluss wird die HTTP-Anfrage als GET-Anfrage an den Server gesendet, wobei die zuvor abgefragten Werte (ISIN, von, bis) an die URL angehängt werden. Es handelt sich um eine synchrone Anfrage, was bedeutet, dass die Webseite wartet, bis die Daten vollständig geladen wurden, bevor sie weiter ausgeführt wird. Hier nun ein weiteres Frontend, diesmal als Java Swing Anwendung unter Verwendung von J-Free-Chart. Rechts oben sind wieder die Parameter einzugeben. Links oben können Sie zusätzliche Indikatoren anzeigen lassen, Gleitende Durchschnitte über verschiedene Zeiträume. Hier sehen Sie den Aufruf des REST-Dienstes und die Konvertierung der JSON-Daten in ein Java-Objekt. Im Vorfeld müssen noch einige Klassen importiert werden. Die Hilfsmethode from-JSON verwendet ihrerseits G-son als Hilfsbibliothek. Noch ein weiteres Frontend für dasselbe Backend, diesmal in Excel. Hier sehen Sie die nötigen Eingaben, eine VBA-Schaltfläche und die Ausgabe in einer Excel-Tabelle aufbereitet. Der VBA-Code wird ausgeführt, wenn die Schaltfläche in Excel angeklickt wird. Zuerst werden verschiedene Variablen deklariert, darunter eine für die HTTP-Anfrage, eine für die Antwort des Servers und eine für den Link, der die Anfrage enthält. Der Link zur Abfrage der Kursreihe wird zusammengesetzt, indem der Basislink mit den Werten aus den Zellen C-zwei, C-drei und C-vier in Excel kombiniert wird. Diese Zellen enthalten die ISIN, das Startdatum von und das Enddatum bis. Eine HTTP-GET-Anfrage wird erstellt, um die Kursreihe-Daten im CSV-Format vom Server abzurufen. Der Content-Type-Header wird auf text-csv (diesmal also kein JSON) gesetzt, um anzugeben, dass die Antwort im CSV-Format erwartet wird. Die Anfrage wird dann an den Server gesendet. Während die Anfrage verarbeitet wird, wartet das Programm, bis der gesamte Inhalt geladen ist, indem es den Status der Anfrage kontinuierlich überprüft. Sobald die Daten vollständig geladen sind, wird die Antwort in der Variable response gespeichert. Dieser VBA-Code verarbeitet die Daten, die in der Variable response gespeichert sind, und fügt sie in das Excel-Arbeitsblatt "Daten" ein. Zuerst wird der Inhalt der response-Variable mithilfe der Funktion Split in einzelne Zeilen aufgeteilt. Jede Zeile wird dabei durch das Zeichen für einen Zeilenumbruch getrennt. Die Anzahl der Zeilen wird ermittelt, und das Arbeitsblatt "Daten" wird zunächst gelöscht, um Platz für die neuen Daten zu schaffen. Anschließend wird eine Schleife verwendet, um jede Zeile zu durchlaufen. Innerhalb dieser Schleife wird jede Zeile erneut aufgeteilt, diesmal anhand des Trennzeichens "Semikolon", um die einzelnen Werte innerhalb der Zeile zu erhalten. Die Anzahl der Werte in jeder Zeile wird ebenfalls ermittelt. Falls eine Zeile tatsächlich Werte enthält, werden diese in die Zellen des Arbeitsblatts "Daten" eingetragen. Dabei wird für jede Zelle das Zahlenformat auf "Text" gesetzt, um sicherzustellen, dass die Werte korrekt als Text behandelt werden. Schließlich wird der Wert in die entsprechende Zelle eingefügt. Und so entsteht die Ausgabe, die Sie schon eben auf einer Folie gesehen haben. Nun ein Fazit zu dem Beispiel. Jede Kommunikation geht von den Clients aus: Der PHP-Server ist passiv und sendet nur nach Aufforderung (Request). Dann greift er auf die dahinter liegende MySQL-Datenbank zu. Das ist gut für die Abfrage von schwach veränderlichen Daten: Vermeiden Sie Polling durch ständigen, automatisierten Reload! Die Kopplung zwischen Frontend und Backend ist sehr schwach: Das ist gut! Es gibt vier Frontend-Beispiele zu demselben Backend! Hier sehen Sie das Richardson-Reifegradmodell (RMM), ein von Leonard Richardson entwickelter Maßstab, der bewertet, wie strikt ein Webservice REST implementiert ist. Das Modell besteht aus vier Ebenen (Levels), die jeweils unterschiedliche Eigenschaften aufweisen. Level null: Hier wird entweder XML-RPC oder SOAP verwendet. Der Service wird über eine einzelne URI angesprochen, und es wird nur eine einzelne HTTP-Methode, wie zum Beispiel POST, verwendet. Level eins: Auf dieser Ebene verwendet der Service verschiedene URIs und Ressourcen, aber weiterhin nur eine einzelne HTTP-Methode, typischerweise POST. Level zwei: Der Service verwendet verschiedene URIs und Ressourcen sowie mehrere HTTP-Methoden, was eine größere Flexibilität und Funktionalität ermöglicht. Level drei: Diese höchste Ebene basiert auf dem Prinzip von HATEOAS (Hypermedia as the Engine of Application State). Der Service verwendet Hypermedia zur Navigation und ermöglicht so eine dynamische Interaktion mit den Ressourcen. Auch hier werden verschiedene URIs und Ressourcen sowie mehrere HTTP-Methoden genutzt. Diese Folie veranschaulicht das Richardson-Reifegradmodell auf Level null anhand eines Beispiels. Auf dieser Ebene wird eine sehr einfache REST-Implementierung dargestellt, bei der der gesamte Service über eine einzige URI angesprochen wird. In diesem Fall handelt es sich um einen appointment-Service. Der Service akzeptiert zwei verschiedene Arten von POST-Anfragen: open-Slot-Request und appointment-Request. Beide Anfragen werden an dieselbe URI gesendet, und die Antwort liefert entweder eine Liste verfügbarer Zeitfenster (open-Slot-List) oder eine Bestätigung des Termins (appointment). Diese Folie zeigt das Richardson-Reifegradmodell auf Level eins, bei dem verschiedene URIs und Ressourcen verwendet werden. Im Gegensatz zu Level null, wo alle Anfragen an eine einzelne URI gesendet wurden, zeigt diese Ebene eine REST-Architektur, die spezifischere URIs für unterschiedliche Ressourcen nutzt. Im Diagramm sind zwei unterschiedliche URIs zu sehen: doctors-m-jones und slots-eins-zwei-drei-vier. Diese URIs repräsentieren spezifische Ressourcen im System. Die erste URI könnte beispielsweise die Ressource eines bestimmten Arztes (mjones) ansprechen, während die zweite URI einen spezifischen Slot oder Terminzeitraum (eins-zwei-drei-vier) darstellt. Trotz der Einführung verschiedener URIs werden immer noch POST-Anfragen für die Interaktion mit dem Service verwendet. Die URI-Struktur ermöglicht jedoch eine genauere Adressierung der Ressourcen, was den Service flexibler und skalierbarer macht. Dies ist der zentrale Unterschied zu Level null, da der Service nun in der Lage ist, verschiedene Ressourcen über unterschiedliche URIs anzusprechen. Diese Folie illustriert das Richardson-Reifegradmodell auf Level zwei, bei dem verschiedene HTTP-Methoden verwendet werden. Im Vergleich zu Level eins, wo nur eine HTTP-Methode (meist POST) verwendet wurde, ermöglicht Level zwei den Einsatz mehrerer HTTP-Methoden, um verschiedene Aktionen auszuführen. Im Diagramm wird gezeigt, dass die GET-Methode verwendet wird, um eine Liste verfügbarer Zeitslots abzurufen. Diese GET-Anfrage enthält Parameter wie Datum und Status, die in der URL übergeben werden, was typisch für eine GET-Anfrage ist, da diese Methode dazu dient, Daten vom Server abzurufen, ohne den Zustand auf dem Server zu verändern. Die Antwort auf diese Anfrage ist eine Statusmeldung (zweihundert OK) zusammen mit der angeforderten Liste von Zeitslots. Darüber hinaus wird die POST-Methode verwendet, um einen neuen Termin zu erstellen. Hier wird eine POST-Anfrage an den Server gesendet, um eine Ressource (in diesem Fall einen Termin) zu erstellen. Die Antwort ist eine Statusmeldung (zweihundert-eins Created), die bestätigt, dass der Termin erfolgreich erstellt wurde, sowie der Ort (URI) der neuen Ressource. Durch die Nutzung unterschiedlicher HTTP-Methoden wie GET und POST wird der Service flexibler und besser an die REST-Prinzipien angepasst, da verschiedene Aktionen klar voneinander getrennt und entsprechend der HTTP-Spezifikation umgesetzt werden. Kommen wir nun zu REST Level drei. Hypermedia as the Engine of Application State (HATEOAS) ist ein Entwurfsprinzip von REST-Architekturen. Bei HATEOAS navigiert der Client einer REST-Schnittstelle ausschließlich über URLs, welche vom Server bereitgestellt werden. Abhängig von der gewählten Repräsentation geschieht die Bereitstellung der URIs über Hypermedia, also zum Beispiel in Form von „href“- und „src“-Attributen bei HTML-Dokumenten beziehungsweise HTML-Snippets, oder in für die jeweilige Schnittstelle definierten und dokumentierten JSON- beziehungsweise XML-Attributen oder Elementen. Abstrakt betrachtet stellen HATEOAS-konforme REST-Services einen endlichen Automaten dar, dessen Zustandsveränderungen durch die Navigation mittels der bereitgestellten URIs erfolgt. Durch HATEOAS ist eine lose Bindung gewährleistet und die Schnittstelle kann verändert werden. Diese Folie zeigt abschließend das Richardson-Reifegradmodell auf Level drei, bei dem das Prinzip von HATEOAS verwendet wird. Im Diagramm wird dargestellt, wie eine GET-Anfrage durchgeführt wird, um eine Liste verfügbarer Zeitslots abzurufen. Neben der Rückgabe der angeforderten Daten (zweihundert OK und die openSlotList) enthält die Antwort auch einen Hypermedia-Link. Dieser Link zeigt auf eine weitere Aktion, die der Client ausführen kann, in diesem Fall das Buchen eines bestimmten Zeitslots. Der Link verweist auf die URI "slots-slots-eins-zwei-drei-vier" und enthält Informationen darüber, welche Aktion dieser Link ermöglicht, hier: book. Zusätzlich wird gezeigt, wie eine POST-Anfrage verwendet wird, um einen Termin zu erstellen, ähnlich wie in Level zwei. Nach der erfolgreichen Erstellung des Termins (zweihundert-eins Created) wird der Ort der neu erstellten Ressource zurückgegeben, in diesem Fall die URL des erstellten Termins. Durch die Verwendung von HATEOAS wird der Client in der Lage, dynamisch auf Ressourcen zuzugreifen und den weiteren Interaktionsverlauf durch die vom Server bereitgestellten Links zu steuern. Dies macht die Anwendung flexibler und reduziert die Notwendigkeit, dass der Client im Voraus alle möglichen Interaktionspfade kennen muss. Auf welchem REST-Level befindet sich das Tradingtool?